﻿// Copyright (c) 2007 Readify Pty. Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Threading;
using BuildMonitor.Properties;

namespace BuildMonitor.Engine
{
	public class BuildWatcher
	{
	    private readonly BuildStoreEventSource eventSource;

        public BuildWatcher(ConsoleText consoleText)
		{
            var teamFoundationServiceProvider = new TfsServiceProvider(Settings.Default.TeamFoundationUrl, consoleText);
            eventSource = new BuildStoreEventSource(teamFoundationServiceProvider, Settings.Default.BuildDefinitionNameExclusionPattern);
		}

		private Thread workerThread;

		private void Worker()
		{
			var events = eventSource.GetListOfBuildStoreEvents();
			if (BuildWatcherInitializing != null)
				BuildWatcherInitializing(this, events);

			while (true)
			{
				try
				{
					var buildStoreEvents = eventSource.GetListOfBuildStoreEvents();
					foreach (var buildEvent in buildStoreEvents)
					{
						ProcessBuildEvent(buildEvent);
					}
				}
				catch (ThreadAbortException)
				{
					return;
				}

				Thread.Sleep(Settings.Default.PollPeriod * 1000);
			}
		}

		private void ProcessBuildEvent(BuildStoreEventArgs buildEvent)
		{
			switch (buildEvent.Type)
			{
				case BuildStoreEventType.Build:
					if (BuildCompletionEvent != null)
						BuildCompletionEvent(this, buildEvent);
					break;
				case BuildStoreEventType.QualityChanged:
					if (BuildQualityChangeEvent != null)
						BuildQualityChangeEvent(this, buildEvent);
					break;
				default:
					throw new Exception("Event was not recognised.");
			}

		}

		public void Start()
		{
			if (workerThread != null)
			{
				throw new Exception("The worker thread has already been started.");
			}

			workerThread = new Thread(Worker);
			workerThread.IsBackground = true;
			workerThread.Start();

		}

		public void Stop()
		{
			if (workerThread == null)
			{
				throw new Exception("The worker thread was not started.");
			}

			if (BuildWatcherStopping != null)
				BuildWatcherStopping(this, new EventArgs());

			workerThread.Abort();
			workerThread = null;
		}

		public event BuildWatcherInitializingHandler BuildWatcherInitializing;
		public event BuildWatcherEventHandler BuildCompletionEvent;
		public event BuildWatcherEventHandler BuildQualityChangeEvent;
		public event BuildWatcherStoppingHandler BuildWatcherStopping;

	}
}